﻿namespace TestConsole
{
    using System;
    using etracks.EntityModels;
    using etracks.Helpers;
    using System.Data.Common;
    using System.Collections.Generic;
    using System.Data;
    using System.Linq;

    class MainClass
    {
        static void calc(Node<double> node)
        {
            node.Value = 1.0d / (1.0d + Math.Pow(Math.E, -(node.Edges.Sum(n => n.Value * n.Node.Value) + node.Bias)));
        }

        public static void Run()
        {
            #region comment out
            //IDatabaseHelper dbHelper = DatabaseHelperFactory.Get(DatabaseType.POSTGRESQL);
            //dbHelper.ConnectionString = ConfigHelper.GetConnectionString("postgresql");
            //dbHelper.Connection.Open();
            //dbHelper.Connection.Close();

            //IDatabaseHelper dbHelper = DatabaseHelperFactory.Get(DatabaseType.POSTGRESQL);
            //dbHelper.ConnectionString = ConfigHelper.GetConnectionString("postgresql");
            ////List<DbParameter> pl = new List<DbParameter>();
            ////pl.Add(dbHelper.GetParameter("name", "Judy"));
            ////DataSet ds = dbHelper.GetDataSet("get_student", pl);

            //using (var conn = dbHelper.Connection)
            //{
            //    //Npgsql.NpgsqlDataAdapter da = new Npgsql.NpgsqlDataAdapter()
            //    Npgsql.NpgsqlCommand cmd = (Npgsql.NpgsqlCommand)conn.CreateCommand();
            //    cmd.CommandType = System.Data.CommandType.StoredProcedure;
            //    cmd.CommandText = "get_student";

            //    Npgsql.NpgsqlParameter p1 = new Npgsql.NpgsqlParameter("name", System.Data.DbType.String, 128);
            //    p1.Value = "Judy";
            //    cmd.Parameters.Add(p1);
            //    List<Npgsql.NpgsqlParameter> p = new List<Npgsql.NpgsqlParameter>();
            //    p.Add(p1);
            //    //System.Data.Common.DbDataAdapter da = new Npgsql.NpgsqlDataAdapter(cmd);
            //    //System.Data.DataSet ds = new System.Data.DataSet();
            //    //da.Fill(ds, "TEST");

            //    conn.Open();
            //    cmd.ExecuteReader(CommandBehavior.CloseConnection);

            //    Npgsql.NpgsqlDataReader dr;
            //    if (dr.HasRows())
            //    {
                    
            //    }
            //}


            //dbHelper.Connection.Close();
            #endregion comment out

            #region TODO: Postgresql helper
            //////////////////////////////////////////////////////////////////////////////////
            //// Setup
            //IDatabaseHelper dbHelper = DatabaseHelperFactory.Get(DatabaseType.POSTGRESQL);
            //dbHelper.ConnectionString = ConfigHelper.GetConnectionString("postgresql");

            //List<DbParameter> pl = null;
            //////////////////////////////////////////////////////////////////////////////////
            ////void AddStudent(Student model);

            //pl = new List<DbParameter>();
            //pl.Add(dbHelper.GetParameter("p_full_name", "Ong Zhi Xian"));
            //pl.Add(dbHelper.GetParameter("p_display_name", "Zhixian"));
            //pl.Add(dbHelper.GetParameter("p_nationality_id", "S0000000Z"));
            //dbHelper.Execute("add_student", pl);


            //////////////////////////////////////////////////////////////////////////////////
            ////void GetStudent(string name);
            
            //pl = new List<DbParameter>();
            //pl.Add(dbHelper.GetParameter("p_full_name", "Ong Zhi Xian"));
            //pl.Add(dbHelper.GetParameter("p_display_name", "Zhixian"));
            //pl.Add(dbHelper.GetParameter("p_nationality_id", "S0000000Z"));
            //dbHelper.Execute("get_student", pl);

            //////////////////////////////////////////////////////////////////////////////////
            ////void RemoveStudent(string id);

            //////////////////////////////////////////////////////////////////////////////////
            ////void UpdateStudent(Student model);

            //////////////////////////////////////////////////////////////////////////////////
            ////void FindStudent(string name);

            #endregion TODO: Postgresql helper

            Graph g = new Graph();

            Node<double> in0 = new Node<double>(0.0d, "in0"); // input value
            Node<double> in1 = new Node<double>(2.0d, "in1"); // input value
            Node<double> in2 = new Node<double>(3.0d, "in2"); // input value

            Node<double> hn0 = new Node<double>(0d, -2.0d, "hn0"); // computed value, bias
            Node<double> hn1 = new Node<double>(0d, -6.0d, "hn1"); // computed value, bias
            Node<double> hn2 = new Node<double>(0d, -1.0d, "hn2"); // computed value, bias
            Node<double> hn3 = new Node<double>(0d, -7.0d, "hn3"); // computed value, bias

            Node<double> on0 = new Node<double>(0d, -2.5d, "on0"); // computed value, bias
            Node<double> on1 = new Node<double>(0d, -5.0d, "on1"); // computed value, bias

            // Setup activation functions
            
            hn0.ComputeValue = Graph.Sigmoid;
            hn1.ComputeValue = Graph.Sigmoid;
            hn2.ComputeValue = Graph.Sigmoid;
            hn3.ComputeValue = Graph.Sigmoid;

            on0.ComputeValue = Graph.HyperTan;
            on1.ComputeValue = Graph.HyperTan;

            ////////////////////////////////////////////////////////////////////////////////
            in0.AddEdge(hn0, 0.1d);
            in0.AddEdge(hn1, 0.2d);
            in0.AddEdge(hn2, 0.3d);
            in0.AddEdge(hn3, 0.4d);

            in1.AddEdge(hn0, 0.5d);
            in1.AddEdge(hn1, 0.6d);
            in1.AddEdge(hn2, 0.7d);
            in1.AddEdge(hn3, 0.8d);

            in2.AddEdge(hn0, 0.9d);
            in2.AddEdge(hn1, 1.0d);
            in2.AddEdge(hn2, 1.1d);
            in2.AddEdge(hn3, 1.2d);

            ////////////////////////////////////////////////////////////////////////////////
            hn0.AddEdge(on0, 1.3d);
            hn0.AddEdge(on1, 1.4d);

            hn1.AddEdge(on0, 1.5d);
            hn1.AddEdge(on1, 1.6d);

            hn2.AddEdge(on0, 1.7d);
            hn2.AddEdge(on1, 1.8d);

            hn3.AddEdge(on0, 1.9d);
            hn3.AddEdge(on1, 2.0d);

            ////////////////////////////////////////////////////////////////////////////////
            // Calculate node value in->hn

            //hn0.Value = 1.0d / (1.0d + Math.Pow(Math.E, -(hn0.Edges.Sum(n => n.Value * n.Node.Value) + hn0.Bias)));
            //hn1.Value = 1.0d / (1.0d + Math.Pow(Math.E, -(hn1.Edges.Sum(n => n.Value * n.Node.Value) + hn1.Bias)));
            //hn2.Value = 1.0d / (1.0d + Math.Pow(Math.E, -(hn2.Edges.Sum(n => n.Value * n.Node.Value) + hn2.Bias)));
            //hn3.Value = 1.0d / (1.0d + Math.Pow(Math.E, -(hn3.Edges.Sum(n => n.Value * n.Node.Value) + hn3.Bias)));

            ////////////////////////////////////////////////////////////////////////////////
            // Calculate node value hn->on

            //on0.Value = Math.Tanh(on0.Edges.Sum(n => n.Value * n.Node.Value) + on0.Bias);
            //on1.Value = Math.Tanh(on1.Edges.Sum(n => n.Value * n.Node.Value) + on1.Bias);

            Console.WriteLine("in0 {0}, {1}", in0.Value, in0.Edges.Count);
            Console.WriteLine("in1 {0}, {1}", in1.Value, in1.Edges.Count);
            Console.WriteLine("in2 {0}, {1}", in2.Value, in2.Edges.Count);

            Console.WriteLine("hn0 {0}, {1}", hn0.Value, hn0.Edges.Count);
            Console.WriteLine("hn1 {0}, {1}", hn1.Value, hn1.Edges.Count);
            Console.WriteLine("hn2 {0}, {1}", hn2.Value, hn2.Edges.Count);
            Console.WriteLine("hn3 {0}, {1}", hn3.Value, hn3.Edges.Count);

            Console.WriteLine("on0 {0}, {1}", on0.Value, on0.Edges.Count);
            Console.WriteLine("on1 {0}, {1}", on1.Value, on1.Edges.Count);

            Console.WriteLine("^^^^^^^^^^Changes");

            // in0.SetValue(5.0d);
            in0.Value = 1.0d;

            Console.WriteLine("in0 {0}, {1}", in0.Value, in0.Edges.Count);
            Console.WriteLine("in1 {0}, {1}", in1.Value, in1.Edges.Count);
            Console.WriteLine("in2 {0}, {1}", in2.Value, in2.Edges.Count);

            Console.WriteLine("hn0 {0}, {1}", hn0.Value, hn0.Edges.Count);
            Console.WriteLine("hn1 {0}, {1}", hn1.Value, hn1.Edges.Count);
            Console.WriteLine("hn2 {0}, {1}", hn2.Value, hn2.Edges.Count);
            Console.WriteLine("hn3 {0}, {1}", hn3.Value, hn3.Edges.Count);

            Console.WriteLine("on0 {0}, {1}", on0.Value, on0.Edges.Count);
            Console.WriteLine("on1 {0}, {1}", on1.Value, on1.Edges.Count);

            Console.ReadLine();
        }

        public static void WorkingGraph()
        {
            Graph g = new Graph();

            Node<double> in0 = new Node<double>(1.0d);
            Node<double> in1 = new Node<double>(2.0d);
            Node<double> in2 = new Node<double>(3.0d);

            Node<double> hn0 = new Node<double>(0d, -2.0d);
            Node<double> hn1 = new Node<double>(0d, -6.0d);
            Node<double> hn2 = new Node<double>(0d, -1.0d);
            Node<double> hn3 = new Node<double>(0d, -7.0d);

            Node<double> on0 = new Node<double>(0d, -2.5d);
            Node<double> on1 = new Node<double>(0d, -5.0d);

            ////////////////////////////////////////////////////////////////////////////////
            // Setting up links
            in0.AddEdge(hn0, 0.1d);
            in0.AddEdge(hn1, 0.2d);
            in0.AddEdge(hn2, 0.3d);
            in0.AddEdge(hn3, 0.4d);

            in1.AddEdge(hn0, 0.5d);
            in1.AddEdge(hn1, 0.6d);
            in1.AddEdge(hn2, 0.7d);
            in1.AddEdge(hn3, 0.8d);

            in2.AddEdge(hn0, 0.9d);
            in2.AddEdge(hn1, 1.0d);
            in2.AddEdge(hn2, 1.1d);
            in2.AddEdge(hn3, 1.2d);


            ////////////////////////////////////////////////////////////////////////////////
            // Setting up links
            hn0.AddEdge(on0, 1.3d);
            hn0.AddEdge(on1, 1.4d);

            hn1.AddEdge(on0, 1.5d);
            hn1.AddEdge(on1, 1.6d);

            hn2.AddEdge(on0, 1.7d);
            hn2.AddEdge(on1, 1.8d);

            hn3.AddEdge(on0, 1.9d);
            hn3.AddEdge(on1, 2.0d);


            ////////////////////////////////////////////////////////////////////////////////
            // Calculate node value in->hn

            hn0.Value = 1.0d / (1.0d + Math.Pow(Math.E, -(hn0.Edges.Sum(n => n.Value * n.Node.Value) + hn0.Bias)));
            hn1.Value = 1.0d / (1.0d + Math.Pow(Math.E, -(hn1.Edges.Sum(n => n.Value * n.Node.Value) + hn1.Bias)));
            hn2.Value = 1.0d / (1.0d + Math.Pow(Math.E, -(hn2.Edges.Sum(n => n.Value * n.Node.Value) + hn2.Bias)));
            hn3.Value = 1.0d / (1.0d + Math.Pow(Math.E, -(hn3.Edges.Sum(n => n.Value * n.Node.Value) + hn3.Bias)));



            ////////////////////////////////////////////////////////////////////////////////
            // Calculate node value hn->on
            on0.Value = Math.Tanh(on0.Edges.Sum(n => n.Value * n.Node.Value) + on0.Bias);
            on1.Value = Math.Tanh(on1.Edges.Sum(n => n.Value * n.Node.Value) + on1.Bias);


            Console.WriteLine("hn0 {0}", hn0.Value);
            Console.WriteLine("hn1 {0}", hn1.Value);
            Console.WriteLine("hn2 {0}", hn2.Value);
            Console.WriteLine("hn3 {0}", hn3.Value);

            Console.WriteLine("on0 {0}", on0.Value);
            Console.WriteLine("on1 {0}", on1.Value);

            Console.ReadLine();
        }
        public static void Main(string[] args)
        {
            Console.WriteLine("[START]");

            Run();

            Console.WriteLine("[END]");
            Console.WriteLine("Press any key to exit.");
            Console.ReadLine();
        }
    }
}
